package com.polaris.live.widget.marqueeview

import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.graphics.drawable.ColorDrawable
import android.text.TextPaint
import android.util.AttributeSet
import android.view.View
import android.view.animation.LinearInterpolator
import com.polaris.live.R
import com.polaris.live.common.util.AppCodeUtils
import java.util.Locale
import kotlin.math.abs

/**
 * SimpleMarqueeView
 */
class SimpleMarqueeView(context: Context, attrs: AttributeSet?) : View(context, attrs) {

    private var density: Float = 2f
    private var scaleDensity: Float = 2f
    private var gravity = 1

    //font size
    private var textSize = 33f

    //font color
    private var textColor = Color.parseColor("#000000")

    //style
    private var typeFace = Typeface.DEFAULT

    //文本
    private var mText = ""

    //compute text width if txtWidth>width  user marquee
    private var txtWidth = 0

    //shadow,if background is not color , that is not useful
    private var shadowWidth = 0f

    //the system marquee textview is 12L
    private var speed = 12L

    //animation delay
    private var delay = 1500L

    //between two texts margin
    private var margin = 0f

    //0 text 1 marquee
    private var showMode = 0
    private var anim: ValueAnimator? = null
    private var animValue: Int = 0

    private var leftShadow: LinearGradient? = null
    private var rightShadow: LinearGradient? = null

    private var paddingRect: Rect = Rect()
    private val shadowPaint by lazy {
        Paint()
    }

    init {
        if (attrs != null) {
            val dm = context.applicationContext.resources.displayMetrics
            density = dm.density
            scaleDensity = dm.scaledDensity

            val a = context.obtainStyledAttributes(
                attrs, R.styleable.SimpleMarqueeView, 0, 0
            )
            textSize = a.getDimension(R.styleable.SimpleMarqueeView_textSize, sp2px(12f).toFloat())
            textColor = a.getColor(R.styleable.SimpleMarqueeView_textColor, Color.parseColor("#000000"))
            when (a.getInt(R.styleable.SimpleMarqueeView_textStyle, 1)) {
                1 -> typeFace = Typeface.DEFAULT
                2 -> typeFace = Typeface.DEFAULT_BOLD
                3 -> typeFace = Typeface.defaultFromStyle(Typeface.ITALIC)
                4 -> typeFace = Typeface.defaultFromStyle(Typeface.BOLD_ITALIC)
            }
            val text = a.getString(R.styleable.SimpleMarqueeView_text) ?: ""
            shadowWidth = a.getDimension(R.styleable.SimpleMarqueeView_shadow_width, dp2px(14f).toFloat())
            margin = a.getDimension(R.styleable.SimpleMarqueeView_margin_txt, dp2px(133f).toFloat())
            speed = a.getInt(R.styleable.SimpleMarqueeView_speed, 12).toLong()
            delay = a.getInt(R.styleable.SimpleMarqueeView_delay, 1500).toLong()
            gravity = a.getInt(R.styleable.SimpleMarqueeView_gravity, 1)
            a.recycle()
            setText(text)
        }
    }

    // if background is not color, it's not useful
    private fun initShadow() {
        if (background is ColorDrawable) {
            val colorD = ColorDrawable((background as? ColorDrawable)?.color ?: 0)
            colorD.alpha = 255
            val sColorInt = colorD.color
            colorD.alpha = 0
            val eColorInt = colorD.color
            if (shadowWidth > 0) {
                leftShadow = LinearGradient(
                    paddingStart.toFloat(),
                    0f,
                    paddingStart.toFloat() + shadowWidth,
                    0f,
                    sColorInt,
                    eColorInt,
                    Shader.TileMode.CLAMP
                )
                rightShadow = LinearGradient(
                    width - paddingEnd.toFloat() - shadowWidth,
                    0f,
                    width - paddingEnd.toFloat(),
                    0f,
                    eColorInt,
                    sColorInt,
                    Shader.TileMode.CLAMP
                )
            }

        }
    }

    private val textPaint by lazy {
        TextPaint().apply {
            this.color = this@SimpleMarqueeView.textColor
            this.textSize = this@SimpleMarqueeView.textSize
            this.typeface = this@SimpleMarqueeView.typeFace
            this.isAntiAlias = true
            if (layoutDirection == LAYOUT_DIRECTION_RTL) {
                this.textLocale = Locale("ar") // 设置为阿拉伯语示例，适应 RTL
//                if (gravity == 1) {
//                    this.textAlign = Paint.Align.RIGHT
//                }

            } else {
                this.textLocale = Locale("en") // 设置为英语示例，适应 LTR
//                if (gravity == 1) {
//                    this.textAlign = Paint.Align.LEFT
//                }

            }
        }
    }

    fun setText(text: String, force: Boolean = false) {
        if (text == mText && !force) return
        this.mText = text
        stopAnim()
        post {
            if (visibility == VISIBLE) {
                initShadow()
                measureTxt()
                switchShowMode()
                show()
            }
        }
    }

    fun setTextColor(color: Int) {
        textColor = color
        textPaint.color = textColor
        invalidate()
    }

    fun getText() = mText

    override fun setVisibility(visibility: Int) {
        if (this@SimpleMarqueeView.visibility == visibility) {
            super.setVisibility(visibility)
        } else {
            super.setVisibility(visibility)
            if (visibility == View.VISIBLE) {
                setText(mText, true)
            } else {
                stopAnim()
            }
        }
    }

    private fun show() {
        animValue = 0
        if (showMode == 0) {
            invalidate()
        } else {
            invalidate()
            startAnim()
        }
    }

    private fun startAnim() {
        stopAnim()
        anim = ValueAnimator.ofInt(0, (txtWidth + margin).toInt())
        anim?.duration = ((txtWidth + margin) * speed).toLong()
        anim?.interpolator = LinearInterpolator()
        anim?.repeatCount = 0
        anim?.addUpdateListener {
            animValue = if (showMode == 0) {
                it.cancel()
                0
            } else {
                it.animatedValue as Int
            }
            invalidate()
        }
        anim?.addListener(object : Animator.AnimatorListener {

            override fun onAnimationStart(animation: Animator) {
            }

            override fun onAnimationEnd(animation: Animator) {
                show()
            }

            override fun onAnimationCancel(animation: Animator) {
            }

            override fun onAnimationRepeat(animation: Animator) {
            }
        })
        anim?.startDelay = delay
        anim?.start()
    }

    private fun stopAnim() {
        anim?.cancel()
        anim?.removeAllListeners()
        anim?.removeAllUpdateListeners()
        anim = null
        animValue = 0
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val x = if (showMode == 1 || gravity == 1) {
            if (AppCodeUtils.isAR()) {
                (width - paddingEnd - txtWidth).toFloat() + animValue.toFloat()
            } else {
                -animValue.toFloat() + paddingStart
            }

        } else {
            paddingStart + (width - paddingStart - paddingEnd - txtWidth) / 2f
        }
        paddingRect.left = paddingStart
        paddingRect.top = paddingTop
        paddingRect.right = width - paddingEnd
        paddingRect.bottom = height - paddingBottom
        canvas.clipRect(paddingRect)
        canvas.drawText(mText, x, textSize + (height - textSize) / 2f - sp2px(1f), textPaint)
        if (showMode == 1) {
            val y = if (AppCodeUtils.isAR()) {
                x - margin - txtWidth
            } else {
                x + margin + txtWidth
            }
            canvas.drawText(mText, y, textSize + (height - textSize) / 2f - sp2px(1f), textPaint)
            if (abs(x) < txtWidth - paddingStart && anim?.isRunning == true) {
                leftShadow?.run {
                    shadowPaint.shader = this
                    canvas.drawRect(
                        paddingStart.toFloat(),
                        0f,
                        paddingStart + shadowWidth,
                        height.toFloat(),
                        shadowPaint
                    )
                }
            }

            rightShadow?.run {
                shadowPaint.shader = this
                canvas?.drawRect(
                    width - paddingEnd.toFloat() - shadowWidth,
                    0f,
                    width - paddingEnd.toFloat(),
                    height.toFloat(),
                    shadowPaint
                )
            }
        }
    }

    private fun switchShowMode() {
        showMode = if (txtWidth + paddingStart + paddingEnd > width) {
            //跑马灯模式
            1
        } else {
            //正常显示
            0
        }
    }

    //compute txt width
    private fun measureTxt() {
        txtWidth = textPaint.measureText(mText).toInt()
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        stopAnim()
    }

    private fun dp2px(dipValue: Float): Int {
        return (dipValue * density + 0.5f).toInt()
    }

    private fun sp2px(spValue: Float): Int {
        return (spValue * scaleDensity + 0.5f).toInt()
    }

    //support height wrap_content
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec)
        if (heightSpecMode == MeasureSpec.AT_MOST) {
            val tMin = dp2px(3f)
            val pTop = if (paddingTop < tMin) tMin else paddingTop
            val pBottom = if (paddingBottom < tMin) tMin else paddingBottom
            setMeasuredDimension(widthSpecSize, (textSize + pTop + pBottom).toInt())
        }
    }

    //if you want  pause anim,use it
    fun pause() {
        anim?.takeIf {
            it.isRunning
        }?.run {
            pause()
        }
    }

    //if you want resume anim,use it
    fun resume() {
        anim?.run {
            resume()
        }
    }

    fun startAndResume() {
        if (anim == null) {
            show()
        } else {
            anim?.run {
                if (this.isPaused) {
                    resume()
                }
            }
        }

    }
}